/***************************************************************************
 *   Copyright (C) 2009 by umbacos@gmail.com                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "udm-common.h"
#define MAXPD 1024

char* dcgi;
char* droo;
char* dbin;
char* dwww;
char* dufb;
char* ddnl;
char* dtrk;
char* fcnf;
char* pidfile;
char* filter;
char* argv0;
char* wget;
char* ctor;
char* mtomb_start;
char* mtomb_stop;
char resp[1000];

char * getPID(char* file);
void * xmalloc(size_t size);
void get_directories(char * file);
void get_post_cookie();
int filter_select(struct dirent *entry);
void send_response(void);
void add_to_response(char* resp);
void init_response(void);
void add_headers(int final);
char * escape_hyphens(char * str, char * ch);
char * pipe_cmd(const char * cmd);
#ifdef DEBUG
char * ltos(long long l);
#endif

char * human_readable(unsigned long long s) {
	char * str = xmalloc(100);

	if (s > 1073741824)
		sprintf(str, "%.1f G", ((float) s) / 1073741824);
	else if (s > 1048576)
		sprintf(str, "%.1f M", ((float) s) / 1048576);
	else if (s > 1024)
		sprintf(str, "%.1f K", ((float) s) / 1024);
	else
		sprintf(str, "%Ld", s);

	return strdup(str);
}

void compose_dnl() {

	struct dirent **namelist;
	struct stat buf;
	struct tm * mtime;
	int n;
	char * ndnl = xmalloc(1000);

	strcpy(ndnl, ddnl);

	if (getenv("FORM_curdir"))
		strncat(ndnl, getenv("FORM_curdir"), 1000 - strlen(ddnl));

	if ((strstr(ndnl, "/..") != NULL) || (chdir(ndnl) != 0)) {
		strcpy(ndnl, ddnl);
		chdir(ndnl);
		add_to_response("curdir: '/',");
	} else {
		sprintf(resp, "curdir: '%s',", getenv("FORM_curdir"));
		add_to_response(resp);
	}

	add_to_response("dnl:[");

	filter = "";
	n = scandir(ndnl, &namelist, (void *) filter_select, alphasort);

	if (n < 0)
		send_message("Can't scan download directory", ndnl);
	else {
		while (n--) {
			stat(namelist[n]->d_name, &buf);

			sprintf(resp, "{file:'%s',", escape_hyphens(namelist[n]->d_name,
					"'"));
			add_to_response(resp);

			if (S_ISDIR ( buf.st_mode ))
				add_to_response("type:'d',");
			else
				add_to_response("type:'f',");

			sprintf(resp, "inode:%lld,", buf.st_ino);
			add_to_response(resp);

			sprintf(resp, "size:'%s',", human_readable(buf.st_size));
			add_to_response(resp);

			mtime = gmtime(&buf.st_mtime);
			sprintf(resp, "date:'%0d/%0d/%d %0d:%0d:%0d'}", mtime->tm_mday,
					mtime->tm_mon, 1900 + mtime->tm_year, mtime->tm_hour,
					mtime->tm_min, mtime->tm_sec);
			add_to_response(resp);

			if (n > 0)
				add_to_response(",");

			free(namelist[n]);
		}

		free(namelist);

		add_to_response("]");
	}
}

int compose_disk() {

	struct statvfs fs;
	unsigned long long usedh;
	unsigned long long avail;
	unsigned long long diskh;
	unsigned long long freeb;

	statvfs(ddnl, &fs);

	diskh = (fs.f_blocks / 1024.0) * fs.f_bsize;
	avail = (fs.f_bavail / 1024.0) * fs.f_bsize;
	freeb = (fs.f_bfree / 1024.0) * fs.f_bsize;
	usedh = diskh - freeb;
	sprintf(resp, "disk:{size:%Lu,used:%Lu,available:%Lu,perc:'%.0f%%'}",
			diskh, usedh, avail, (usedh * 100.0 / (usedh + avail)));
	add_to_response(resp);
}

int compose_JSON(char* typo) {
	char* entry;

	struct dirent **namelist;
	int n;
	int cnt;

	add_to_response(typo + 1);
	add_to_response(":[");

#ifdef DEBUG
	mylog("compose_JSON:", typo);
#endif
	filter = typo;
	if ((n = scandir(dtrk, &namelist, (void *) filter_select, NULL)) < 0)
		send_message("Can't scan tracker directory:\n", dtrk);
#ifdef DEBUG
	mylog(ltos(n), " found");
#endif

	cnt = 0;
	while (n--) {
		if (strlen(entry = getPID(namelist[n]->d_name)) != 0)
			cnt++;
		sprintf(resp, "{obj:\"%s@%s\"}", namelist[n]->d_name, entry);
		add_to_response(resp);
		if (n > 0)
			add_to_response(",");
		free(namelist[n]);
	}

	free(namelist);
	add_to_response("]");
	filter = "";
	return cnt;
}

int filter_dir(struct dirent *entry) {

	struct stat buf;
	if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0))
		return (FALSE);

	stat(entry->d_name, &buf);
	if (S_ISDIR ( buf.st_mode ))
		return (TRUE);
	return (FALSE);
}

int compose_tree(char* path) {
	char* entry;

	struct dirent **namelist;
	int n;
	int cnt;
	char ppath[1000];
	char pd[MAXPD];

#ifdef DEBUG
	mylog("adding:", path);
#endif
	add_to_response("<li><span class='");
	add_to_response(getenv("FORM_file"));
	add_to_response("' id='");
	add_to_response(escape_hyphens(path + strlen(ddnl), "'"));
	add_to_response("/'>");
	add_to_response(escape_hyphens((char *) basename(path), "'"));
	add_to_response("</span>");

	filter = "";

	chdir(path);

	if ((n = scandir(path, &namelist, (void *) filter_dir, NULL)) < 0) {
		if (errno == ENOMEM)
			send_message("Insufficient Memory to complete the operation: ",
					path);

		send_message("Can't scan directory:", path);
	}

	cnt = n;

	while (n--) {
		if (n == (cnt - 1))
			add_to_response("<ul>");
		sprintf(ppath, "%s/%s", path, namelist[n]->d_name);
		compose_tree(ppath);
		chdir(path);
		if (n == 0)
			add_to_response("</ul>");
		free(namelist[n]);
	}

	add_to_response("</li>");

	free(namelist);
	return;
}

int quick_check_how_many(char * typo) {

	struct dirent **namelist;
	struct stat buf;
	struct tm * mtime;
	int r;
	int n;
	time_t tt;

	filter = typo;
	chdir(dtrk);
	n = scandir(dtrk, &namelist, (void *) filter_dir, NULL);
	r = 0;
	while (n--) {
		tt = time(0);
		if (stat(namelist[n]->d_name, &buf) == 0)
			if (tt - buf.st_mtime < 3)
				r++;
		free(namelist[n]);
	}
	free(namelist);
	return r;
}

#ifdef DEBUG

int display_info(const char *fpath, const struct stat *sb, int tflag) {
	if (tflag == FTW_D)
		mylog(fpath, "");
	return 0; /* To tell nftw() to continue */
}

#endif

int main(int argc, char** argv) {

	int totTor = 0;
	int totWgt = 0;
	char * pids;
	char * tr;
	int r;
	FILE* fp;

	setlocale(LC_ALL, "");

	memset(resp, 0, 1000);

	get_directories(strdup(argv[0]));
	get_post_cookie();

	init_response();
	add_headers(TRUE);

	if (tr = getenv("FORM_cmd")) {
		if (strstr(tr, CMD_TREE) != 0) {
#ifdef DEBUG
			ftw(".", display_info, 20);
#endif
			add_to_response("<ul rel=open id=");
			add_to_response(getenv("FORM_file"));
			add_to_response(">");
			compose_tree(ddnl);
			add_to_response("</ul>");
		}
	} else {
#ifdef DEBUG
		mylog("start status dump...", "");
#endif
		add_to_response("{");
		if (tr = getenv("FORM_t")) {
			if (tr[0] != '0') {
				compose_JSON(FILTER_INF);
				add_to_response(",");
				compose_JSON(FILTER_AMU);
				add_to_response(",");
				totTor = compose_JSON(FILTER_TOR);
				add_to_response(",");
				totWgt = compose_JSON(FILTER_WGT);
				add_to_response(",");
			} else {
				totTor = quick_check_how_many(FILTER_TOR);
				totWgt = quick_check_how_many(FILTER_WGT);
			}
		} else {
			totTor = quick_check_how_many(FILTER_TOR);
			totWgt = quick_check_how_many(FILTER_WGT);
		}

		sprintf(resp, "torrents:%d,wgets:%d", totTor, totWgt);
		add_to_response(resp);
		add_to_response(",");
		compose_disk();

		if (tr = getenv("FORM_f")) {
			if (tr[0] != '0') {
				add_to_response(",");
				compose_dnl();
			}
		}
		add_to_response("}");
	}

	send_response();
}
